package com.whjz.redis;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.*;

import com.alibaba.fastjson.JSON;
import com.whjz.utils.ConstansUtil;
import com.whjz.utils.SpringContextUtils;
import com.whjz.utils.StringConstantUtil;

import lombok.Data;

public class RedisUtils {

	@SuppressWarnings("rawtypes")
	private static RedisTemplate template = SpringContextUtils.getBeanByName("redisTemplate");

	// 向redis里存入数据
	@SuppressWarnings("unchecked")
	public static void setKey(String key, String value) {
		ValueOperations<String, String> ops = template.opsForValue();
		ops.set(key, value);
	}

	public static String getHash(String key, String hashKey) {
		HashOperations<String, String, String> operations = template.opsForHash();
		return operations.get(key, hashKey);
	}

	public static void putHash(String key, String hashKey, String value) {
		HashOperations<String, String, String> operations = template.opsForHash();
		operations.put(key, hashKey, value);
	}

	// 从redis中取数据
	@SuppressWarnings("unchecked")
	public static String getValue(String key) {
		ValueOperations<String, String> ops = template.opsForValue();
		return ops.get(key);
	}

	// 向redis里存入数据和设置缓存时间（以秒为单位）
	@SuppressWarnings("unchecked")
	public static void setKeyAndCacheTime(String key, String value, long timeout) {
		ValueOperations<String, String> ops = template.opsForValue();
		ops.set(key, value, timeout, TimeUnit.SECONDS);
		
	}

	// 向redis存入的数据做-1 操作
	@SuppressWarnings("unchecked")
	public static void setValueDecrement(String key) {
		template.boundValueOps(key).increment(-1);
	}

	// 向redis存入的数据做+1 操作
	@SuppressWarnings("unchecked")
	public static void setValueIncrement(String key) {
		template.boundValueOps(key).increment(+1);
	}

	// 根据key获取过期时间
	@SuppressWarnings("unchecked")
	public static Long getDeadLine(String key) {
		return template.getExpire(key);
	}

	// 根据key删除缓存
	@SuppressWarnings("unchecked")
	public static void deleteByKey(String key) {
		template.delete(key);
	}

	// 检查key是否存在，返回boolean值
	@SuppressWarnings("unchecked")
	public static Boolean existKey(String key) {
		return template.hasKey(key);
	}

	/**
	 * 获取分页数据
	 * @param key
	 * @param pageNo
	 * @param rowsPerPage 每页记录数
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Set<String> getPageDate(String key,int pageNo,int rowsPerPage) {
		int start = (pageNo-1)*rowsPerPage;
		int end = pageNo*rowsPerPage -1;
		ZSetOperations<String, String> options = template.opsForZSet();
		Set<String> pageDates = options.range(key, start, end);
		return pageDates;
	}
	
	/**
	 * 添加有序集合数据
	 * @param key
	 * @param dataList
	 */
	@SuppressWarnings("unchecked")
	public static void zAddDate(String key,List<Object> dataList) {
		ZSetOperations<String, Object> options = template.opsForZSet();
		int index = 0;
//		Set<TypedTuple<String>> dataSet = new HashSet<TypedTuple<String>>();
		for(Object obj : dataList) {
			options.add(key,obj, index++);
		}
	}
	
	/**
	 * 设置key超时时间
	 * @param key
	 * @param expireTime
	 * @param timeUnit
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static boolean setExpireTime(String key,int expireTime,TimeUnit timeUnit) {
		return template.expire(key,expireTime,timeUnit);

	}
	/**
	 * 查询有序集合总记录数
	 * @param key
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static long getTotal(String key) {
		ZSetOperations<String, String> options = template.opsForZSet();
		Long total = options.count(key, 0, Integer.MAX_VALUE);
		return total;
	}
	
	/**
	 * 获取用户信息
	 * 
	 * @param clientSeqNo
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map getUserInfo(String clientSeqNo) {
		ValueOperations<String, String> ops = template.opsForValue();
		String userRedis = ops.get(StringConstantUtil.USER + clientSeqNo);
		if (StringUtils.isEmpty(userRedis)) {
			return null;
		}
		Map map = JSON.parseObject(userRedis, Map.class);
		return map;
	}
	
	/**
	 * 根据设备号获取用户信息
	 * @param deviceId
	 * @return
	 */
	/** add by zhangxueliang for(bug)327 设备免登录的会调用登录接口多次。 20181210 begin*/
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map getUserInfoByDeviceId(String deviceId) {
		ValueOperations<String, String> operations  = template.opsForValue();
		String deviceIdRedis = operations.get(StringConstantUtil.DEVICE+deviceId);
		if(StringUtils.isEmpty(deviceIdRedis)) {
			return null;
		}
		Map map = JSON.parseObject(deviceIdRedis,Map.class);
		return map;
	}
	/** add by zhangxueliang for(bug)327 设备免登录的会调用登录接口多次。 20181210 end*/
	/**
	 * 销毁用户信息
	 * 
	 * @param clientSeqNo
	 */
	public static void destroyUserInfo(String clientSeqNo) {
		deleteByKey(StringConstantUtil.TOKEN + clientSeqNo);		//清空TOKEN信息
		deleteByKey(StringConstantUtil.USER + clientSeqNo);			//清空用户信息
		deleteByKey(ConstansUtil.LAST_ORDER + clientSeqNo);			//清空交易对象   add by liweibin for (108)登出清理用户数据  20181205
	}

	/**
	 * 存入list数据
	 * @param key
	 * @param list
	 */
	public static void setList(String key,List list){
		ListOperations ops = template.opsForList();
		ops.leftPushAll(key,list);
	}
	
	/**
	 * 存入覆盖list数据
	 * @param key
	 * @param list
	 */
	public static void setNewList(String key,List list){
		//删除key
		template.delete(key);
		ListOperations ops = template.opsForList();
		ops.leftPushAll(key,list);
	}

	/**
	 * 存入一个过去过期的值
	 * @param key
	 * @param list
	 * @param time
	 */
	public static void setList(String key,List list,Long time){
		ListOperations ops = template.opsForList();
		template.delete(key);
		ops.leftPushAll(key,list);
		template.expire(key,time,TimeUnit.SECONDS);
	}

	/**
	 * 获取list列表  starIndex,endIndex为-1的时候查询所有的
	 * @param key
	 * @param starIndex
	 * @param endIndex
	 * @return
	 */
	public static List getList(String key,Long starIndex,Long endIndex){
		if(starIndex==null){
			starIndex = 0L;
		}
		if(endIndex==null){
			endIndex = -1L;
		}
		ListOperations ops = template.opsForList();
		return ops.range(key,starIndex,endIndex);
	}

	/**
	 * 设置set的集合
	 * @param key
	 * @param set
	 */
	public static void setList(String key,Set set){
		SetOperations ops = template.opsForSet();
		ops.difference(key,set);
	}

	/**
	 * 设置set集合的过期时间
	 * @param key
	 * @param set
	 * @param time
	 */
	public static void setList(String key,Set set,Long time){
		SetOperations ops = template.opsForSet();
		ops.difference(key,set);
		template.expire(key,time,TimeUnit.SECONDS);
	}

	/**
	 * 获取set集合
	 * @param key
	 * @return
	 */
	public static Set getSetList(String key){
		SetOperations ops = template.opsForSet();
		return ops.members(key);
	}


	/**
	 * 存入list数据
	 * @param key
	 * @param object
	 */
	public static void setSecondTimeList(String key,Object object,int secondTime){
		ListOperations ops = template.opsForList();
		//先根据key查询是否有值
		List list = ops.range(key,0L,-1L);
		if(list!=null){
			//判断值是否过期如果过期就移出
			Iterator<Map> it = list.iterator();
			while(it.hasNext()){
				Map maps = (Map)it.next();;
				Date date = (Date)maps.get("time");
				if(date!=null){
					//比较的结果 -1是小于，0，等于，1是大于
					int covert =Calendar.getInstance().getTime().compareTo(date);
					if(covert!=-1){
						//删除当前值
						it.remove();
					}
				}
			}
			Map<String,Object> map = new HashMap<String,Object>();
			Calendar calendar = Calendar.getInstance();
			calendar.add(Calendar.SECOND,secondTime);
			map.put("time",calendar.getTime());
			map.put("list",object);
			list.add(map);
		}
		//删除key
		template.delete(key);
		//保存key
		ops.leftPushAll(key,list);
	}


	/**
	 *
	 * @param key redis取的集合
	 * @param desc true 降序 false 升序
	 * @return
	 */
	public static List getTimeList(String key,boolean desc){
		ListOperations ops = template.opsForList();
		//先根据key查询是否有值
		List list = ops.range(key,0L,-1L);
		List resultList = new ArrayList();
		//取出集合
		for(int i=0;i<list.size();i++){
			Map map = (Map)list.get(i);
			resultList.add(map.get("list"));
		}
		//去掉重复数据
		Set<Object> set = new HashSet<Object>();
		for (Object object :resultList){
			set.add(object);
		}
		//判断重复的数量
		List<SortBean> coutList = new ArrayList<SortBean>();
		for(Object o : set){
			int cont = 0;
			for (Object lobject : resultList){
				//相等
				if(o.equals(lobject)){
					cont = cont+1;
				}
			}
			SortBean sortBean = new SortBean();
			sortBean.setCount(cont);
			sortBean.setObject(o);
			coutList.add(sortBean);
		}
		if(desc){
			//从大到小
			Collections.sort(coutList, new Comparator<SortBean>() {
				@Override
				public int compare(SortBean o1, SortBean o2) {
					if(o1.getCount()> o2.getCount()){
						return 1;
					}
					if(o1.getCount() ==o2.getCount()){
						return 0;
					}
					return -1;
				}
			});
		}else{
			//排序从小到大
			Collections.sort(coutList, new Comparator<SortBean>() {
				@Override
				public int compare(SortBean o1, SortBean o2) {
					if(o1.getCount()< o2.getCount()){
						return 1;
					}
					if(o1.getCount() ==o2.getCount()){
						return 0;
					}
					return -1;
				}
			});
		}
		//排序后的集合
		List<Object>  descList = new ArrayList<Object>();
		for (SortBean s : coutList){
			descList.add(s.getObject());
		}
		return descList;
	}
	

	/**
	 * 储蓄罐获取返回给硬件的信息
	 * 
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map getBoxInfo(String deviceId) {
		ValueOperations<String, String> ops = template.opsForValue();
		String userRedis = ops.get(StringConstantUtil.BOX + deviceId);
		if (StringUtils.isEmpty(userRedis)) {
			return null;
		}
		Map map = JSON.parseObject(userRedis, Map.class);
		return map;
	}
	
	/** add by fanda for(bug)170 设备查询利率会循环调用接口多次。 20190118 start*/
	/**
	 * 获取利率
	 * 
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map getDepositInterestRateDate(String key) {
		ValueOperations<String, String> ops = template.opsForValue();
		String InterestRateDate = ops.get(key);
		if (StringUtils.isEmpty(InterestRateDate)) {
			return null;
		}
		Map map = JSON.parseObject(InterestRateDate, Map.class);
		return map;
	}
	/** add by fanda for(bug)170 设备查询利率会循环调用接口多次。 20190118 end*/
	

}

/***
 * 计算排序的实体
 */
@Data
class  SortBean{

	private int count;

	private Object object;
}

